package com.duojuhe.websocket.message;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.duojuhe.common.enums.chat.ImChatEnum;
import com.duojuhe.common.exception.base.DuoJuHeException;
import com.duojuhe.common.result.ErrorCodes;
import com.duojuhe.coremodule.chat.im.handle.ChatHandleCommonKit;
import com.duojuhe.websocket.EventCodes;
import com.duojuhe.websocket.socket.SocketMessage;
import com.duojuhe.websocket.socket.SocketSessionCache;
import com.duojuhe.websocket.socket.SocketSessionUser;
import com.duojuhe.websocket.socket.SocketUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * 消息处理
 */
@Slf4j
public class MessageHandle extends TextWebSocketHandler {
    @Resource
    private ChatHandleCommonKit chatHandleCommonKit;
    //队列大小
    private int queueSize;

    public MessageHandle(int queueSize) {
        this.queueSize = queueSize;
    }

    /**
     * socket 接收到消息
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        log.debug("socket receive message, sessionId={},ip={},message={}", session.getId(),
                SocketUtil.getClientIp(session), message.getPayload());
        // 接受的文本信息
        String requestMessage = message.getPayload();
        try {
            if (StringUtils.isBlank(requestMessage)) {
                SocketUtil.sendMessageBySession(session, SocketMessage.eventError(ErrorCodes.SOCKET_REQUEST_BODY_ERROR.getMessage()));
                return;
            }
            //先判断用户是否存在，如果不存在直接关闭socket
            SocketSessionUser socketSessionUser = SocketSessionCache.getSessionUserBySessionId(session.getId());
            if (socketSessionUser == null) {
                log.error("socketSessionUser 用户缓存不存在，直接关闭, cannot get socketSessionUser by sessionId, sessionId={}, ip={}, isOpen={}", session.getId(), SocketUtil.getClientIp(session), session.isOpen());
                session.close(CloseStatus.SERVICE_RESTARTED);
                return;
            }
            //心跳标识data
            String heartbeat = SocketUtil.SOCKET_PING.toLowerCase();
            //【兼容老系统】检测正确的心跳
            if (StringUtils.equals(requestMessage.toLowerCase(), heartbeat)) {
                log.info("Socket收到心跳数据, sessionId={},ip={}", session.getId(), SocketUtil.getClientIp(session));
                socketSessionUser.setHeartDate(new Date());
                SocketUtil.sendMessageBySession(session, SocketMessage.eventHeartbeat());
                return;
            }
            //将字符串转成json
            JSONObject bodyJson = JSON.parseObject(requestMessage);
            if (bodyJson == null) {
                return;
            }
            //获取消息事件类型
            String eventType = bodyJson.getString("event");
            //获取消息中的内容体
            String data = bodyJson.getString("data");
            //检查正确标准格式心跳
            if (EventCodes.EVENT_HEARTBEAT.getEvent().equals(eventType)
                    && StringUtils.isNotBlank(data) && heartbeat.equals(data.toLowerCase())) {
                log.info("Socket收到心跳数据, sessionId={},ip={}", session.getId(), SocketUtil.getClientIp(session));
                socketSessionUser.setHeartDate(new Date());
                SocketUtil.sendMessageBySession(session, SocketMessage.eventHeartbeat());
                return;
            }
            if (EventCodes.EVENT_TALK.getEvent().equals(eventType)) {
                //添加聊天记录
                chatHandleCommonKit.onConsumeTalk(bodyJson, socketSessionUser);
            } else if (EventCodes.EVENT_KEYBOARD.getEvent().equals(eventType)) {
                //键盘事件
                chatHandleCommonKit.onConsumeKeyboard(bodyJson, socketSessionUser);
            } else {
                SocketUtil.sendMessageBySession(session, SocketMessage.eventError(ErrorCodes.SOCKET_REQUEST_BODY_ERROR.getMessage()));
            }
        } catch (Exception e) {
            log.error("socket received message process fail, message={}", requestMessage, e);
            if (e instanceof DuoJuHeException) {
                SocketUtil.sendMessageBySession(session, SocketMessage.eventError(e.getMessage()));
            } else {
                SocketUtil.sendMessageBySession(session, SocketMessage.eventError(ErrorCodes.SOCKET_REQUEST_BODY_ERROR.getMessage()));
            }
        }
    }


    /**
     * 新连接打开
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        //构建新用户
        SocketSessionUser socketSessionUser = new SocketSessionUser(session, this.queueSize);
        Integer onlineYes = ImChatEnum.IM_YES_NO.YES.getKey();
        chatHandleCommonKit.onConsumeOnlineStatus(onlineYes, socketSessionUser);
        // 加入到缓存队列中
        SocketSessionCache.addSessionUserCache(session.getId(), socketSessionUser);
        log.info("新连接打开, sessionId={},ip={},totalCount={},queueSize={}", session.getId(), SocketUtil.getClientIp(session), SocketSessionCache.getSessionUserCacheCount(), this.queueSize);

    }

    /**
     * socket 传输异常
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        SocketUtil.handleTransportError(session, exception);
    }

    /**
     * socket 关闭
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        SocketSessionUser socketSessionUser = SocketSessionCache.getSessionUserBySessionId(session.getId());
        if (socketSessionUser == null) {
            log.error("socketSessionUser is null while socket close, sessionId={}, ip={}, statusCode={}, statusReason={}, totalCount={}", session.getId(), SocketUtil.getClientIp(session), status.getCode(), status.getReason(), SocketSessionCache.getSessionUserCacheCount());
        } else {
            //是在线标识
            Integer onlineNo = ImChatEnum.IM_YES_NO.NO.getKey();
            chatHandleCommonKit.onConsumeOnlineStatus(onlineNo, socketSessionUser);
            List<Runnable> runnableList = socketSessionUser.getThreadPoolExecutor().shutdownNow();
            SocketSessionCache.removeSessionUserBySessionId(session.getId());
            log.info("a session close, sessionId={}, ip={},  notExecuteCount={}, statusCode={}, statusReason={}, totalCount={}", session.getId(), SocketUtil.getClientIp(session), runnableList.size(), status.getCode(), status.getReason(), SocketSessionCache.getSessionUserCacheCount());
        }
        SocketUtil.release(session);
    }

    /**
     * 是否分段发送消息
     */
    @Override
    public boolean supportsPartialMessages() {
        return false;
    }


}